package com.zmc.common.aspectj;

import com.zmc.common.annotation.PreventRepeatSubmit;
import com.zmc.common.constant.CacheConstants;
import com.zmc.common.enums.RequestSourceEnum;
import com.zmc.common.exception.base.BusinessException;
import com.zmc.common.utils.SpelUtil;
import com.zmc.common.utils.redis.RedisCache;
import com.zmc.common.utils.token.AuthTokenService;
import com.zmc.common.utils.uuid.IdUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * @Author：zmc
 * @Date：2024/11/11 14:26
 * 防止表单等重复提交
 */

@Component
@Aspect
public class PreventRepeatSubmitAspect {

    public static final Logger log = LoggerFactory.getLogger(PreventRepeatSubmit.class);

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private AuthTokenService authTokenService;

    @Pointcut("@within(com.zmc.common.annotation.PreventRepeatSubmit) || @annotation(com.zmc.common.annotation.PreventRepeatSubmit)")
    public void methodAspect() {
    }


    @Around(value = "methodAspect()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        String key = analysisKey(point);
        String value = IdUtils.fastUUID();
        if (!redisCache.tryLock(key, value, CacheConstants.LOCK_KEY_EXPIRE_TIME, TimeUnit.SECONDS)) {
            throw new BusinessException("正在拼命加载中...");
        }
        try {
            return point.proceed();
        } finally {
            redisCache.unLock(key, value);
        }
    }

    /**
     * 解析注解key的规则
     * */
    public String analysisKey(ProceedingJoinPoint point) {
        //类名
        String targetName = point.getTarget().getClass().getName();
        //方法名
        String methodName = point.getSignature().getName();
        //参数
        Object[] arguments = point.getArgs();
        //通过反射获取示例对象
        Class<?> targetClass = null;
        try {
            targetClass = Class.forName(targetName);
        } catch (ClassNotFoundException e) {
            throw new BusinessException("解析注解key的规则异常");
        }
        String key = "";
        PreventRepeatSubmit repeatSubmit = null;
        //通过实例对象方法数组
        Method[] methods = targetClass.getMethods();
        for (Method method : methods) {
            //判断方法名是不是一样
            if (method.getName().equals(methodName)) {
                //对比参数数组的长度
                Class<?>[] clazz = method.getParameterTypes();
                if (clazz.length == arguments.length) {
                    //类名 + 方法名
                    key = "lock:" + targetName + ":" + method.getName() + ":";
                    repeatSubmit = method.getAnnotation(PreventRepeatSubmit.class);
                    break;
                }
            }
        }
        if (repeatSubmit != null) {
            //是否开启spEL(缓存key策略)
            if (repeatSubmit.openSpEL() && repeatSubmit.key().contains("#")) {
                //判断key如果是以'#'开始,则根据SpEL表达式获取key
                key = key + SpelUtil.generateKeyBySpEL(repeatSubmit.key(), point);
            }
            RequestSourceEnum source = repeatSubmit.source();
            if (repeatSubmit.lockByPerson()) {
                String userId = null;
                if (RequestSourceEnum.MANAGE.equals(source)) {
                    userId = authTokenService.getUserInfo().getUserId() + "";
                } else {
                    userId = authTokenService.getMemberInfo().getMemberId();
                }
                key = key + userId;
            }
        }
        return key;
    }

}
